import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:flutter/foundation.dart' show kIsWeb;
// 只在非web端引入dart:io
// ignore: uri_does_not_exist
import 'dart:io' as io;
import 'package:path_provider/path_provider.dart';
import 'package:archive/archive.dart';
import 'package:gbk_codec/gbk_codec.dart';
import 'package:epubx/epubx.dart';
import 'package:flutter/material.dart' as flutter;
import 'dart:typed_data';
import 'package:provider/provider.dart';
import 'theme_provider.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => ThemeProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    final themeProvider = Provider.of<ThemeProvider>(context);
    return MaterialApp(
      title: '书阅', // 修改应用名
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: themeProvider.primaryColor,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
        scaffoldBackgroundColor:
            themeProvider.primaryColor == Colors.white ? Colors.white : null,
        appBarTheme: AppBarTheme(
          backgroundColor:
              themeProvider.primaryColor == Colors.white ? Colors.white : null,
          foregroundColor:
              themeProvider.primaryColor == Colors.white ? Colors.black : null,
        ),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: themeProvider.primaryColor,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
        scaffoldBackgroundColor: Colors.black,
        appBarTheme: const AppBarTheme(
          backgroundColor: Colors.black,
          foregroundColor: Colors.white,
        ),
      ),
      themeMode: themeProvider.isDarkMode ? ThemeMode.dark : ThemeMode.light,
      home: MainPage(),
    );
  }
}

class Book {
  final String name;
  final String type; // txt or epub
  final String? path; // 非web端本地路径
  final String? contentBase64; // 仅web端txt
  final bool isTemp; // web端epub临时导入

  Book({
    required this.name,
    required this.type,
    this.path,
    this.contentBase64,
    this.isTemp = false,
  });

  Map<String, dynamic> toJson() => {
    'name': name,
    'type': type,
    'path': path,
    'contentBase64': contentBase64,
    'isTemp': isTemp,
  };

  factory Book.fromJson(Map<String, dynamic> json) => Book(
    name: json['name'],
    type: json['type'],
    path: json['path'],
    contentBase64: json['contentBase64'],
    isTemp: json['isTemp'] ?? false,
  );
}

// 工具方法：章节分割
List<Chapter> splitChapters(String content) {
  final chapterReg = RegExp(
    r'(第[\d一二三四五六七八九十百千]+章[\s\S]*?)(?=第[\d一二三四五六七八九十百千]+章|\$)',
    multiLine: true,
  );
  final matches = chapterReg.allMatches(content);
  if (matches.isEmpty) {
    // 没有章节分隔，整体作为一个章节
    return [Chapter(title: '正文', content: content)];
  }
  return matches.map((m) {
    final text = m.group(0)!;
    final titleMatch = RegExp(r'第[\d一二三四五六七八九十百千]+章[^\n\r]*').firstMatch(text);
    final title = titleMatch?.group(0) ?? '章节';
    final body = text.replaceFirst(title, '').trim();
    return Chapter(title: title, content: body);
  }).toList();
}

// 章节信息（只记录标题和起止位置）
class ChapterInfo {
  final String title;
  final int start;
  final int end;
  ChapterInfo({required this.title, required this.start, required this.end});
}

// 分批异步分割章节目录
Future<void> splitChaptersInfoBatch(
  String content,
  int batchSize,
  void Function(List<ChapterInfo>, bool isLast) onBatch,
) async {
  final chapterReg = RegExp(
    r'(第[\d一二三四五六七八九十百千]+章[\s\S]*?)(?=第[\d一二三四五六七八九十百千]+章|\$)',
    multiLine: true,
  );
  final matches = chapterReg.allMatches(content).toList();
  if (matches.isEmpty) {
    onBatch([ChapterInfo(title: '正文', start: 0, end: content.length)], true);
    return;
  }
  int total = matches.length;
  for (int offset = 0; offset < total; offset += batchSize) {
    final List<ChapterInfo> batch = [];
    for (int i = offset; i < (offset + batchSize) && i < total; i++) {
      final m = matches[i];
      final start = m.start;
      final end =
          (i + 1 < matches.length) ? matches[i + 1].start : content.length;
      final text = content.substring(m.start, m.end);
      final titleMatch = RegExp(
        r'第[\d一二三四五六七八九十百千]+章[^\n\r]*',
      ).firstMatch(text);
      final title = titleMatch?.group(0) ?? '章节';
      batch.add(ChapterInfo(title: title, start: start, end: end));
    }
    bool isLast = (offset + batchSize) >= total;
    onBatch(batch, isLast);
    await Future.delayed(const Duration(milliseconds: 80)); // 控制分批节奏
  }
}

// 获取指定章节内容
String getChapterContent(String content, ChapterInfo info) {
  final text = content.substring(info.start, info.end);
  final titleMatch = RegExp(r'第[\d一二三四五六七八九十百千]+章[^\n\r]*').firstMatch(text);
  final title = titleMatch?.group(0) ?? info.title;
  final body = text.replaceFirst(title, '').trim();
  return body;
}

// 工具方法：读取内容
Future<String> readBookContent(Book book) async {
  if (book.contentBase64 != null) {
    // Web端
    final bytes = base64Decode(book.contentBase64!);
    try {
      return utf8.decode(bytes);
    } catch (_) {
      try {
        return gbk.decode(bytes);
      } catch (e) {
        return '解码失败，可能不是UTF-8或GBK编码：$e';
      }
    }
  } else if (book.isTemp && kIsWeb) {
    // Web端临时epub
    if (_WebTempEpubHolder.bytes == null) return '临时漫画内容已丢失，请重新导入';
    // 这里只做演示，实际应解析epub内容

    return '[epub漫画内容，大小：${_WebTempEpubHolder.bytes!.lengthInBytes}字节]';
  } else if (book.path != null) {
    // 非Web端
    if (kIsWeb) return '不支持在Web端读取本地文件';
    try {
      return await _readFileFromPath(book.path!);
    } catch (e) {
      return '读取失败：$e';
    }
  } else {
    return '无内容';
  }
}

Future<String> _readFileFromPath(String path) async {
  if (kIsWeb) return '不支持在Web端读取本地文件';
  try {
    final file = io.File(path);
    final bytes = await file.readAsBytes();
    // 自动检测编码
    try {
      final text = utf8.decode(bytes);
      print('[DEBUG] _readFileFromPath: 检测到UTF-8编码');
      return text;
    } catch (_) {
      try {
        final text = gbk.decode(bytes);
        print('[DEBUG] _readFileFromPath: 检测到GBK编码');
        return text;
      } catch (e) {
        print('[ERROR] _readFileFromPath: 解码失败 $e');
        return '解码失败，可能不是UTF-8或GBK编码：$e';
      }
    }
  } catch (e) {
    return '读取失败：$e';
  }
}

Future<List<Uint8List>> extractEpubImages(Book book) async {
  Uint8List? bytes;
  if (book.isTemp && kIsWeb) {
    bytes = _WebTempEpubHolder.bytes;
  } else if (book.path != null) {
    if (kIsWeb) return [];
    try {
      final file = io.File(book.path!);
      bytes = await file.readAsBytes();
    } catch (_) {
      return [];
    }
  }
  if (bytes == null) return [];
  final archive = ZipDecoder().decodeBytes(bytes);
  // 只保留图片文件
  final images =
      archive.files
          .where((f) => !f.isFile ? false : _isImageFile(f.name))
          .toList();
  // 按文件名排序
  images.sort((a, b) => a.name.compareTo(b.name));
  return images.map((f) => f.content as Uint8List).toList();
}

bool _isImageFile(String name) {
  final lower = name.toLowerCase();
  return lower.endsWith('.jpg') ||
      lower.endsWith('.jpeg') ||
      lower.endsWith('.png') ||
      lower.endsWith('.gif') ||
      lower.endsWith('.webp');
}

class Chapter {
  final String title;
  final String content;
  Chapter({required this.title, required this.content});
}

class EpubChapter {
  final String title;
  final String? textContent;
  final List<Uint8List>? images;
  EpubChapter({required this.title, this.textContent, this.images});
}

// ComicChapter增加fileName字段（可为null）
class ComicChapter {
  final String title;
  final String? htmlContent;
  final String? fileName;
  final List<dynamic> subChapters;
  ComicChapter({
    required this.title,
    this.htmlContent,
    this.fileName,
    this.subChapters = const [],
  });
}

class BookDetailPage extends StatefulWidget {
  final Book book;
  const BookDetailPage({super.key, required this.book});

  @override
  State<BookDetailPage> createState() => _BookDetailPageState();
}

// 平台判断工具
bool isDesktop() {
  if (kIsWeb) return true;
  try {
    return io.Platform.isMacOS || io.Platform.isWindows || io.Platform.isLinux;
  } catch (_) {
    return false;
  }
}

// BookDetailPage漫画阅读支持，传递imagesMap
class _BookDetailPageState extends State<BookDetailPage> {
  List<ChapterInfo> _chapterInfos = [];
  String? _fullContent;
  final Map<int, String> _chapterContentCache = {};
  int _selectedChapter = 0;
  bool _loading = true;
  String? _error;
  List<EpubChapter> _epubChapters = [];
  int _selectedEpubChapter = 0;
  bool _isEpub = false;
  List<ComicChapter> _comicChapters = [];
  Map<String, EpubByteContentFile> _comicImagesMap = {};
  bool _isComic = false;
  // 搜索相关
  String _searchQuery = '';
  List<int> _searchResults = [];
  final TextEditingController _searchController = TextEditingController();
  final ScrollController _contentScrollController = ScrollController();
  // 阅读设置
  ReadingSettings _readingSettings = ReadingSettings();
  // 目录分批加载相关
  bool _chapterBatchLoading = false;
  bool _chapterBatchFinished = false;
  int _chapterBatchOffset = 0;
  final int _chapterBatchSize = 50;
  String? _fullContentForBatch;
  final ScrollController _chapterListController = ScrollController();
  bool _chapterSheetCollapsed = false;
  final FocusNode _focusNode = FocusNode();
  final FocusNode _searchFieldFocusNode = FocusNode();

  @override
  void initState() {
    super.initState();
    _chapterListController.addListener(_onChapterListScroll);
    _loadContent();
    _loadReadingSettings();
  }

  void _onChapterListScroll() {
    if (_chapterListController.position.pixels >=
        _chapterListController.position.maxScrollExtent - 40) {
      if (_chapterBatchLoading == false && !_chapterBatchFinished) {
        print('[DEBUG] _onChapterListScroll: 触发加载下一批章节');
        _loadNextChapterBatch();
      }
    }
  }

  Future<void> _loadContent() async {
    print(
      '[DEBUG] _loadContent: 开始加载内容, book=${widget.book.name}, type=${widget.book.type}',
    );
    setState(() {
      _loading = true;
      _error = null;
      _chapterBatchLoading = false;
      _chapterBatchFinished = false;
      _chapterInfos = [];
      _chapterBatchOffset = 0;
      _fullContentForBatch = null;
    });
    try {
      if (widget.book.type == 'epub') {
        print('[DEBUG] _loadContent: epub类型，开始解析漫画/文本章节');
        final (comicChapters, imagesMap) = await parseComicEpub(widget.book);
        if (comicChapters.isNotEmpty) {
          print('[DEBUG] _loadContent: 解析到漫画章节 count=${comicChapters.length}');
          setState(() {
            _comicChapters = comicChapters;
            _comicImagesMap = imagesMap;
            _isComic = true;
            _loading = false;
          });
          return;
        }
        final chapters = await parseEpubChapters(widget.book);
        print('[DEBUG] _loadContent: 解析到epub文本章节 count=${chapters.length}');
        if (chapters.isEmpty) {
          setState(() {
            _error = '未找到章节';
            _loading = false;
          });
        } else {
          setState(() {
            _epubChapters = chapters;
            _isEpub = true;
            _loading = false;
          });
        }
      } else if (widget.book.path != null) {
        // 本地txt文件一律用 splitChaptersStream + _readFileFromPath
        final filePath = widget.book.path!;
        final file = io.File(filePath);
        final fileLength = await file.length();
        print(
          '[DEBUG] _loadContent: 本地txt文件, 用splitChaptersStream分割, size=$fileLength',
        );
        double progress = 0;
        setState(() {
          _loading = true;
          _error = null;
        });
        final chapters = await splitChaptersStream(
          filePath,
          onProgress: (p) {
            progress = p;
            setState(() {
              _error = null;
              _loading = true;
              _chapterBatchLoading = false;
              _chapterBatchFinished = false;
              _chapterInfos = [];
              _chapterBatchOffset = 0;
              _fullContentForBatch = null;
              _error = '正在分割章节... ${(p * 100).toStringAsFixed(1)}%';
            });
          },
        );
        print(
          '[DEBUG] _loadContent: splitChaptersStream分割完成, count=${chapters.length}',
        );
        for (int i = 0; i < chapters.length; i++) {
          print(
            '[DEBUG] 章节 $i: title="${chapters[i].title}", start=${chapters[i].start}, end=${chapters[i].end}',
          );
        }
        final fullContent = await _readFileFromPath(filePath);
        print(
          '[DEBUG] _loadContent: _readFileFromPath 完成, 内容长度=${fullContent.length}',
        );
        setState(() {
          _chapterInfos = chapters;
          _fullContent = fullContent;
          print(
            '[DEBUG] setState: _fullContent 赋值, 长度=${_fullContent?.length}',
          );
          _loading = false;
          _error = null;
        });
        print('[DEBUG] _loadContent: 调用 _loadChapterContent(0)');
        _loadChapterContent(0);
        return;
      } else {
        // web端/contentBase64才用 readBookContent
        final sw = Stopwatch()..start();
        String content = await readBookContent(widget.book);
        print(
          '[DEBUG] _loadContent: 读取txt内容完成, length=${content.length}, 耗时: ${sw.elapsedMilliseconds}ms',
        );
        setState(() {
          _fullContent = content;
          _chapterInfos = [];
          _loading = false;
          _chapterBatchLoading = false;
          _chapterBatchFinished = false;
          _chapterBatchOffset = 0;
          _fullContentForBatch = content;
        });
        print('[DEBUG] _loadContent: 小文件, 用isolate分割章节');
        final sw2 = Stopwatch()..start();
        final chapters = await splitChaptersInIsolate(content);
        print(
          '[DEBUG] _loadContent: isolate分割章节完成, count=${chapters.length}, 耗时: ${sw2.elapsedMilliseconds}ms',
        );
        setState(() {
          _chapterInfos = chapters;
        });
        _loadChapterContent(0);
      }
    } catch (e) {
      print('[ERROR] _loadContent: 加载失败: $e');
      setState(() {
        _error = e.toString();
        _loading = false;
        _chapterBatchLoading = false;
        _chapterBatchFinished = false;
      });
    }
  }

  void _loadNextChapterBatch() {
    if (_fullContentForBatch == null) return;
    print(
      '[DEBUG] _loadNextChapterBatch: offset=$_chapterBatchOffset, batchSize=$_chapterBatchSize',
    );
    setState(() {
      _chapterBatchLoading = true;
    });
    splitChaptersInfoBatch(_fullContentForBatch!, _chapterBatchSize, (
      List<ChapterInfo> batch,
      bool isLast,
    ) {
      print(
        '[DEBUG] _loadNextChapterBatch: 本批次章节数=${batch.length}, isLast=$isLast',
      );
      setState(() {
        _chapterInfos.addAll(batch);
        _chapterBatchLoading = false;
        _chapterBatchFinished = isLast;
        _chapterBatchOffset += batch.length;
      });
      if (_chapterInfos.length == batch.length && _chapterInfos.isNotEmpty) {
        _loadChapterContent(0);
      }
    });
  }

  Future<void> _loadChapterContent(int idx) async {
    print(
      '[DEBUG] _loadChapterContent: 入口, idx=$idx, _fullContent is null? ${_fullContent == null}',
    );
    print(
      '[DEBUG] _loadChapterContent: 请求章节 idx=$idx, 总章节=${_chapterInfos.length}',
    );
    if (_chapterContentCache.containsKey(idx)) {
      print('[DEBUG] _loadChapterContent: 命中缓存 idx=$idx');
      return;
    }
    if (_fullContent == null) {
      print('[WARN] _loadChapterContent: _fullContent为空');
      return;
    }
    final info = _chapterInfos[idx];
    final sw = Stopwatch()..start();
    final body = getChapterContent(_fullContent!, info);
    print(
      '[DEBUG] _loadChapterContent: 解析章节内容 idx=$idx, title=${info.title}, 耗时: ${sw.elapsedMilliseconds}ms',
    );
    setState(() {
      _chapterContentCache[idx] = body;
      _chapterContentCache.removeWhere(
        (key, _) => (key < idx - 1) || (key > idx + 1),
      );
    });
    if (idx + 1 < _chapterInfos.length &&
        !_chapterContentCache.containsKey(idx + 1)) {
      final nextInfo = _chapterInfos[idx + 1];
      final nextBody = getChapterContent(_fullContent!, nextInfo);
      _chapterContentCache[idx + 1] = nextBody;
      print('[DEBUG] _loadChapterContent: 预缓存下一章 idx=${idx + 1}');
    }
  }

  Future<void> _loadReadingSettings() async {
    final settings = await ReadingSettingsManager.loadSettings();
    setState(() {
      _readingSettings = settings;
    });
  }

  // 创建应用了阅读设置的文本显示组件
  Widget _buildStyledText(String text) {
    // 分割段落
    final paragraphs = text.split('\n\n');
    final isDark = Theme.of(context).brightness == Brightness.dark;
    return Container(
      color:
          isDark
              ? const Color(0xFF2C2C2C)
              : _getBackgroundColor(_readingSettings.backgroundColor),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children:
            paragraphs.map((paragraph) {
              return Padding(
                padding: EdgeInsets.only(
                  bottom: _readingSettings.paragraphSpacing,
                ),
                child: Text(
                  paragraph.trim(),
                  style: TextStyle(
                    fontSize: _readingSettings.fontSize,
                    fontFamily:
                        _readingSettings.fontFamily == '系统默认'
                            ? null
                            : _readingSettings.fontFamily,
                    height: _readingSettings.lineHeight,
                    color:
                        isDark
                            ? Colors.white
                            : (_readingSettings.backgroundColor == 'dark'
                                ? Colors.white
                                : Colors.black),
                  ),
                ),
              );
            }).toList(),
      ),
    );
  }

  Color _getBackgroundColor(String colorName) {
    switch (colorName) {
      case 'white':
        return Colors.white;
      case 'beige':
        return const Color(0xFFF5F5DC);
      case 'lightYellow':
        return const Color(0xFFFFF8DC);
      case 'lightGreen':
        return const Color(0xFFF0FFF0);
      case 'lightBlue':
        return const Color(0xFFF0F8FF);
      case 'lightGray':
        return const Color(0xFFF5F5F5);
      case 'dark':
        return const Color(0xFF2C2C2C);
      default:
        return Colors.white;
    }
  }

  void _showChapterSheet() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      _chapterSheetCollapsed = prefs.getBool('chapterSheetCollapsed') ?? false;
    });
    print('[DEBUG] _showChapterSheet: 打开目录弹窗, 折叠状态=$_chapterSheetCollapsed');
    showModalBottomSheet(
      context: context,
      builder:
          (ctx) => StatefulBuilder(
            builder:
                (context, setModalState) => SafeArea(
                  child:
                      _chapterInfos.isEmpty
                          ? const Center(
                            child: Padding(
                              padding: EdgeInsets.all(16.0),
                              child: CircularProgressIndicator(),
                            ),
                          )
                          : Column(
                            children: [
                              Padding(
                                padding: const EdgeInsets.all(10),
                                child: TextField(
                                  decoration: InputDecoration(
                                    hintText: '搜索章节...',
                                    prefixIcon: Icon(Icons.search, size: 20),
                                    filled: true,
                                    fillColor:
                                        Theme.of(context).brightness ==
                                                Brightness.dark
                                            ? const Color(0xFF232323)
                                            : Colors.grey[100],
                                    contentPadding: EdgeInsets.symmetric(
                                      vertical: 8,
                                    ),
                                    border: OutlineInputBorder(
                                      borderRadius: BorderRadius.circular(6),
                                      borderSide: BorderSide.none,
                                    ),
                                    isDense: true,
                                  ),
                                  onChanged: (val) {
                                    setModalState(() {
                                      _searchQuery = val.trim();
                                      if (_searchQuery.isEmpty) {
                                        _searchResults = [];
                                      } else {
                                        _searchResults =
                                            List.generate(
                                                  _chapterInfos.length,
                                                  (i) => i,
                                                )
                                                .where(
                                                  (i) => _chapterInfos[i].title
                                                      .contains(_searchQuery),
                                                )
                                                .toList();
                                      }
                                      print(
                                        '[DEBUG] 目录搜索: query=$_searchQuery, 命中章节数=${_searchResults.length}',
                                      );
                                    });
                                  },
                                ),
                              ),
                              Align(
                                alignment: Alignment.centerRight,
                                child: IconButton(
                                  icon: Icon(
                                    _chapterSheetCollapsed
                                        ? Icons.expand_more
                                        : Icons.expand_less,
                                  ),
                                  tooltip:
                                      _chapterSheetCollapsed ? '展开目录' : '折叠目录',
                                  onPressed: () async {
                                    setModalState(() {
                                      _chapterSheetCollapsed =
                                          !_chapterSheetCollapsed;
                                    });
                                    final prefs =
                                        await SharedPreferences.getInstance();
                                    prefs.setBool(
                                      'chapterSheetCollapsed',
                                      _chapterSheetCollapsed,
                                    );
                                    print(
                                      '[DEBUG] 目录折叠切换: 折叠状态=$_chapterSheetCollapsed',
                                    );
                                  },
                                ),
                              ),
                              if (!_chapterSheetCollapsed)
                                Expanded(
                                  child: ListView.builder(
                                    controller: _chapterListController,
                                    itemCount:
                                        _searchQuery.isEmpty
                                            ? _chapterInfos.length + 1
                                            : _searchResults.length + 1,
                                    itemBuilder: (context, idx) {
                                      final realIdx =
                                          _searchQuery.isEmpty
                                              ? idx
                                              : (idx < _searchResults.length
                                                  ? _searchResults[idx]
                                                  : idx);
                                      if (idx <
                                          (_searchQuery.isEmpty
                                              ? _chapterInfos.length
                                              : _searchResults.length)) {
                                        return ListTile(
                                          title: Text(
                                            _chapterInfos[realIdx].title,
                                            maxLines: 1,
                                            overflow: TextOverflow.ellipsis,
                                            style: const TextStyle(
                                              fontSize: 15,
                                            ),
                                          ),
                                          selected: realIdx == _selectedChapter,
                                          onTap: () {
                                            setState(() {
                                              _selectedChapter = realIdx;
                                            });
                                            print(
                                              '[DEBUG] 目录点击: 跳转章节 idx=$realIdx, title=${_chapterInfos[realIdx].title}',
                                            );
                                            _loadChapterContent(realIdx);
                                            Navigator.pop(context);
                                          },
                                        );
                                      } else {
                                        if (_chapterBatchFinished) {
                                          return const Padding(
                                            padding: EdgeInsets.symmetric(
                                              vertical: 12,
                                            ),
                                            child: Center(child: Text('已全部加载')),
                                          );
                                        } else {
                                          return const Padding(
                                            padding: EdgeInsets.symmetric(
                                              vertical: 12,
                                            ),
                                            child: Center(
                                              child:
                                                  CircularProgressIndicator(),
                                            ),
                                          );
                                        }
                                      }
                                    },
                                  ),
                                ),
                            ],
                          ),
                ),
          ),
    );
  }

  // 移动端手势翻页（已去除动画）
  void _handleSwipe(DragEndDetails details) {
    if (details.primaryVelocity! > 0) {
      // 向右滑动，上一章
      if (_selectedChapter > 0) {
        setState(() {
          _selectedChapter--;
        });
        _loadChapterContent(_selectedChapter);
      }
    } else if (details.primaryVelocity! < 0) {
      // 向左滑动，下一章
      if (_selectedChapter < _chapterInfos.length - 1) {
        setState(() {
          _selectedChapter++;
        });
        _loadChapterContent(_selectedChapter);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_isComic) {
      return ComicReaderPage(
        chapters: _comicChapters,
        imagesMap: _comicImagesMap,
      );
    }
    return Scaffold(
      appBar: AppBar(
        title:
            _isEpub
                ? Text(widget.book.name)
                : (_chapterInfos.isNotEmpty
                    ? Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          widget.book.name,
                          style: const TextStyle(fontSize: 16),
                        ),
                        Text(
                          '${_chapterInfos[_selectedChapter].title}  (${_selectedChapter + 1}/${_chapterInfos.length})',
                          style: TextStyle(
                            fontSize: 13,
                            color: Colors.white70,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ],
                    )
                    : Text(widget.book.name)),
        actions: [
          if (!(isDesktop() || widget.book.type == 'epub'))
            IconButton(
              icon: const Icon(Icons.menu_book),
              tooltip: '目录',
              onPressed: _chapterInfos.isEmpty ? null : _showChapterSheet,
            ),
          IconButton(
            icon: const Icon(Icons.settings),
            tooltip: '阅读设置',
            onPressed: () async {
              await showDialog(
                context: context,
                builder:
                    (ctx) => Dialog(
                      child: SizedBox(
                        width: isDesktop() ? 600 : double.infinity,
                        height: isDesktop() ? 600 : null,
                        child: ReadingSettingsPage(
                          onSettingsChanged: () async {
                            await _loadReadingSettings();
                            setState(() {});
                          },
                        ),
                      ),
                    ),
              );
            },
          ),
        ],
      ),
      body:
          _loading
              ? const Center(child: CircularProgressIndicator())
              : _error != null
              ? Center(child: Text('加载失败: $_error'))
              : _isEpub
              ? Row(
                children: [
                  // 目录
                  Container(
                    width: 120,
                    height: double.infinity,
                    color:
                        Theme.of(context).brightness == Brightness.dark
                            ? const Color(0xFF2C2C2C)
                            : _getBackgroundColor(
                              _readingSettings.backgroundColor,
                            ),
                    child: ListView.builder(
                      itemCount: _epubChapters.length,
                      itemBuilder:
                          (context, idx) => ListTile(
                            title: Text(
                              _epubChapters[idx].title,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: const TextStyle(fontSize: 13),
                            ),
                            selected: idx == _selectedEpubChapter,
                            onTap: () {
                              setState(() {
                                _selectedEpubChapter = idx;
                              });
                            },
                          ),
                    ),
                  ),
                  // 内容
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(16.0),
                      child:
                          _epubChapters[_selectedEpubChapter].textContent !=
                                  null
                              ? SingleChildScrollView(
                                child: _buildStyledText(
                                  _epubChapters[_selectedEpubChapter]
                                      .textContent!,
                                ),
                              )
                              : PageView.builder(
                                itemCount:
                                    _epubChapters[_selectedEpubChapter]
                                        .images
                                        ?.length ??
                                    0,
                                itemBuilder: (context, idx) {
                                  final img =
                                      _epubChapters[_selectedEpubChapter]
                                          .images![idx];
                                  return Center(
                                    child: flutter.Image.memory(
                                      img,
                                      fit: BoxFit.contain,
                                    ),
                                  );
                                },
                              ),
                    ),
                  ),
                ], // Row的children闭合
              ) // Row闭合
              : isDesktop()
              ? Row(
                children: [
                  // 目录（含搜索框）
                  Padding(
                    padding: EdgeInsets.only(left: 16, top: 16, bottom: 16),
                    child: Material(
                      elevation: 8,
                      borderRadius: BorderRadius.circular(14),
                      color:
                          Theme.of(context).brightness == Brightness.dark
                              ? const Color(0xFF2C2C2C)
                              : _getBackgroundColor(
                                _readingSettings.backgroundColor,
                              ),
                      child: Container(
                        width: 190,
                        height: double.infinity,
                        padding: EdgeInsets.symmetric(vertical: 8),
                        child: Column(
                          children: [
                            // 搜索框
                            Padding(
                              padding: const EdgeInsets.all(10),
                              child: TextField(
                                controller: _searchController,
                                decoration: InputDecoration(
                                  hintText: '搜索章节...',
                                  prefixIcon: Icon(Icons.search, size: 20),
                                  filled: true,
                                  fillColor:
                                      Theme.of(context).brightness ==
                                              Brightness.dark
                                          ? const Color(0xFF232323)
                                          : Colors.grey[100],
                                  contentPadding: EdgeInsets.symmetric(
                                    vertical: 8,
                                  ),
                                  border: OutlineInputBorder(
                                    borderRadius: BorderRadius.circular(6),
                                    borderSide: BorderSide.none,
                                  ),
                                  isDense: true,
                                ),
                                onChanged: (val) {
                                  setState(() {
                                    _searchQuery = val.trim();
                                    if (_searchQuery.isEmpty) {
                                      _searchResults = [];
                                    } else {
                                      _searchResults =
                                          List.generate(
                                                _chapterInfos.length,
                                                (i) => i,
                                              )
                                              .where(
                                                (i) => _chapterInfos[i].title
                                                    .contains(_searchQuery),
                                              )
                                              .toList();
                                    }
                                  });
                                },
                              ),
                            ),
                            // 章节列表
                            Expanded(
                              child: ListView.separated(
                                itemCount:
                                    _searchQuery.isEmpty
                                        ? _chapterInfos.length
                                        : _searchResults.length,
                                separatorBuilder:
                                    (_, __) => Divider(
                                      height: 1,
                                      color: Colors.grey[200],
                                    ),
                                itemBuilder: (context, idx) {
                                  final realIdx =
                                      _searchQuery.isEmpty
                                          ? idx
                                          : _searchResults[idx];
                                  final selected = realIdx == _selectedChapter;
                                  return InkWell(
                                    onTap: () {
                                      setState(() {
                                        _selectedChapter = realIdx;
                                        _searchQuery = '';
                                        _searchController.clear();
                                        _searchResults = [];
                                      });
                                      _loadChapterContent(realIdx);
                                      _contentScrollController.jumpTo(0);
                                    },
                                    child: Container(
                                      color:
                                          selected
                                              ? Theme.of(context)
                                                  .colorScheme
                                                  .primary
                                                  .withAlpha(30)
                                              : Colors.transparent,
                                      height: 40,
                                      child: Row(
                                        children: [
                                          Container(
                                            width: 4,
                                            height: 24,
                                            color:
                                                selected
                                                    ? Theme.of(
                                                      context,
                                                    ).colorScheme.primary
                                                    : Colors.transparent,
                                          ),
                                          SizedBox(width: 8),
                                          Expanded(
                                            child: Text(
                                              _chapterInfos[realIdx].title,
                                              style: TextStyle(
                                                fontWeight:
                                                    selected
                                                        ? FontWeight.bold
                                                        : FontWeight.normal,
                                                color:
                                                    Theme.of(
                                                              context,
                                                            ).brightness ==
                                                            Brightness.dark
                                                        ? Colors.white
                                                        : (selected
                                                            ? Theme.of(context)
                                                                .colorScheme
                                                                .primary
                                                            : Colors.black87),
                                                fontSize: 15,
                                              ),
                                              maxLines: 1,
                                              overflow: TextOverflow.ellipsis,
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                  );
                                },
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                  // 内容
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Column(
                        children: [
                          // 顶部章节标题+进度
                          if (_chapterInfos.isNotEmpty)
                            Padding(
                              padding: const EdgeInsets.only(bottom: 8.0),
                              child: Text(
                                '${_chapterInfos[_selectedChapter].title}  (${_selectedChapter + 1}/${_chapterInfos.length})',
                                style: TextStyle(
                                  fontSize: 15,
                                  fontWeight: FontWeight.bold,
                                  color:
                                      Theme.of(context).brightness ==
                                              Brightness.dark
                                          ? Colors.white
                                          : Colors.black,
                                ),
                              ),
                            ),
                          // 正文内容（已去除翻页动画）
                          Expanded(
                            child: SingleChildScrollView(
                              controller: _contentScrollController,
                              child: _buildStyledText(
                                _chapterContentCache[_selectedChapter] ??
                                    '（本章节无内容）',
                              ),
                            ),
                          ),
                          if (isDesktop() || kIsWeb)
                            Row(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              children: [
                                ElevatedButton(
                                  onPressed:
                                      _selectedChapter > 0
                                          ? () {
                                            setState(() {
                                              _selectedChapter--;
                                            });
                                            _loadChapterContent(
                                              _selectedChapter,
                                            );
                                            _contentScrollController.jumpTo(0);
                                          }
                                          : null,
                                  child: const Text('上一章'),
                                ),
                                ElevatedButton(
                                  onPressed:
                                      _selectedChapter <
                                              _chapterInfos.length - 1
                                          ? () {
                                            setState(() {
                                              _selectedChapter++;
                                            });
                                            _loadChapterContent(
                                              _selectedChapter,
                                            );
                                            _contentScrollController.jumpTo(0);
                                          }
                                          : null,
                                  child: const Text('下一章'),
                                ),
                              ],
                            ),
                        ],
                      ),
                    ),
                  ),
                ],
              )
              : GestureDetector(
                onHorizontalDragEnd: _handleSwipe,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: SingleChildScrollView(
                    child: _buildStyledText(
                      _chapterContentCache[_selectedChapter] ?? '（本章节无内容）',
                    ),
                  ),
                ),
              ),
    );
  }
}

// 修改书架，点击进入详情
class BookshelfPage extends StatefulWidget {
  const BookshelfPage({super.key});

  @override
  State<BookshelfPage> createState() => _BookshelfPageState();
}

class _BookshelfPageState extends State<BookshelfPage> {
  List<Book> _books = [];
  bool _loading = true;
  bool _isGrid = false; // 列表/网格切换
  String _search = '';
  final TextEditingController _searchController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _loadBooks();
  }

  Future<void> _loadBooks() async {
    final prefs = await SharedPreferences.getInstance();
    final booksJson = prefs.getStringList('books') ?? [];
    setState(() {
      _books = booksJson.map((e) => Book.fromJson(json.decode(e))).toList();
      _loading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    final List<Widget> bookTiles = [];
    // Web端临时epub显示
    if (kIsWeb && _WebTempEpubHolder.bytes != null) {
      final tempBook = Book(name: '临时导入漫画', type: 'epub', isTemp: true);
      bookTiles.add(
        ListTile(
          leading: const Icon(Icons.image, color: Colors.orange),
          title: const Text('临时导入漫画 (epub)'),
          subtitle: const Text('仅本次会话有效'),
          onTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => BookDetailPage(book: tempBook)),
            );
          },
        ),
      );
    }
    // 正常书籍
    final filteredBooks =
        _search.isEmpty
            ? _books
            : _books.where((b) => b.name.contains(_search)).toList();
    bookTiles.addAll(
      filteredBooks.map(
        (book) => ListTile(
          leading: Icon(book.type == 'txt' ? Icons.menu_book : Icons.image),
          title: Text(book.name),
          subtitle: Text(book.type == 'txt' ? '小说 (txt)' : '漫画 (epub)'),
          onTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => BookDetailPage(book: book)),
            );
          },
        ),
      ),
    );
    return Scaffold(
      appBar: AppBar(
        title: const Text('书阅'),
        actions: [
          IconButton(
            icon: Icon(_isGrid ? Icons.list : Icons.grid_view),
            tooltip: _isGrid ? '切换为列表' : '切换为网格',
            onPressed: () {
              setState(() {
                _isGrid = !_isGrid;
              });
            },
          ),
        ],
      ),
      body:
          _loading
              ? const Center(child: CircularProgressIndicator())
              : Column(
                children: [
                  // 顶部搜索框
                  Padding(
                    padding: const EdgeInsets.fromLTRB(12, 12, 12, 0),
                    child: TextField(
                      controller: _searchController,
                      decoration: InputDecoration(
                        hintText: '搜索书籍...',
                        prefixIcon: const Icon(Icons.search),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(8),
                          borderSide: BorderSide.none,
                        ),
                        filled: true,
                        fillColor:
                            Theme.of(context).brightness == Brightness.dark
                                ? const Color(0xFF232323)
                                : Colors.grey[100],
                        isDense: true,
                        contentPadding: const EdgeInsets.symmetric(
                          vertical: 10,
                          horizontal: 12,
                        ),
                      ),
                      onChanged: (val) {
                        setState(() {
                          _search = val.trim();
                        });
                      },
                    ),
                  ),
                  const SizedBox(height: 8),
                  // 书籍列表/网格
                  Expanded(
                    child:
                        filteredBooks.isEmpty &&
                                !(kIsWeb && _WebTempEpubHolder.bytes != null)
                            ? const Center(child: Text('暂无书籍'))
                            : _isGrid
                            ? Padding(
                              padding: const EdgeInsets.all(12.0),
                              child: GridView.builder(
                                shrinkWrap: true,
                                clipBehavior: Clip.hardEdge,
                                itemCount: filteredBooks.length,
                                gridDelegate:
                                    const SliverGridDelegateWithFixedCrossAxisCount(
                                      crossAxisCount: 3,
                                      childAspectRatio: 0.75,
                                      crossAxisSpacing: 8,
                                      mainAxisSpacing: 8,
                                    ),
                                itemBuilder: (context, idx) {
                                  final book = filteredBooks[idx];
                                  return Center(
                                    child: SizedBox(
                                      width: double.infinity,
                                      height: 170, // 固定卡片高度（原210，减小空白）
                                      child: Material(
                                        color: Colors.transparent,
                                        child: InkWell(
                                          borderRadius: BorderRadius.circular(
                                            10,
                                          ),
                                          onTap: () {
                                            Navigator.push(
                                              context,
                                              MaterialPageRoute(
                                                builder:
                                                    (_) => BookDetailPage(
                                                      book: book,
                                                    ),
                                              ),
                                            );
                                          },
                                          child: Card(
                                            elevation: 3,
                                            shape: RoundedRectangleBorder(
                                              borderRadius:
                                                  BorderRadius.circular(10),
                                            ),
                                            child: Column(
                                              crossAxisAlignment:
                                                  CrossAxisAlignment.center,
                                              children: [
                                                // 封面区域（暂无封面用占位）
                                                Container(
                                                  height: 120,
                                                  width: double.infinity,
                                                  decoration: BoxDecoration(
                                                    color: Colors.grey[200],
                                                    borderRadius:
                                                        const BorderRadius.vertical(
                                                          top: Radius.circular(
                                                            10,
                                                          ),
                                                        ),
                                                  ),
                                                  child: Center(
                                                    child: Column(
                                                      mainAxisAlignment:
                                                          MainAxisAlignment
                                                              .center,
                                                      children: [
                                                        Icon(
                                                          book.type == 'epub'
                                                              ? Icons.image
                                                              : Icons.menu_book,
                                                          size: 48,
                                                          color:
                                                              Colors.grey[400],
                                                        ),
                                                        const SizedBox(
                                                          height: 8,
                                                        ),
                                                        Text(
                                                          '暂无封面',
                                                          style: TextStyle(
                                                            fontSize: 12,
                                                            color:
                                                                Colors
                                                                    .grey[500],
                                                          ),
                                                        ),
                                                      ],
                                                    ),
                                                  ),
                                                ),
                                                // 书名
                                                Padding(
                                                  padding:
                                                      const EdgeInsets.symmetric(
                                                        vertical: 8,
                                                        horizontal: 6,
                                                      ),
                                                  child: Text(
                                                    book.name,
                                                    maxLines: 2,
                                                    overflow:
                                                        TextOverflow.ellipsis,
                                                    textAlign: TextAlign.center,
                                                    style: const TextStyle(
                                                      fontWeight:
                                                          FontWeight.bold,
                                                      fontSize: 15,
                                                    ),
                                                  ),
                                                ),
                                                // 类型
                                                Text(
                                                  book.type == 'txt'
                                                      ? '小说 (txt)'
                                                      : '漫画 (epub)',
                                                  style: TextStyle(
                                                    fontSize: 12,
                                                    color: Colors.grey[600],
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ),
                                      ),
                                    ),
                                  );
                                },
                              ),
                            )
                            : ListView(children: bookTiles),
                  ),
                ],
              ),
    );
  }
}

// 在 SettingsPage增加夜间模式开关
class SettingsPage extends StatelessWidget {
  const SettingsPage({super.key});

  Future<void> _importBook(BuildContext context, String type) async {
    FileType fileType = FileType.custom;
    List<String> allowedExtensions = type == 'txt' ? ['txt'] : ['epub'];
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      type: fileType,
      allowedExtensions: allowedExtensions,
      withData: kIsWeb, // Web端需要bytes
    );
    if (result != null) {
      final file = result.files.single;
      final prefs = await SharedPreferences.getInstance();
      final booksJson = prefs.getStringList('books') ?? [];
      Book newBook;
      if (kIsWeb) {
        if (type == 'txt') {
          if (file.bytes == null) {
            if (!context.mounted) return;
            ScaffoldMessenger.of(
              context,
            ).showSnackBar(const SnackBar(content: Text('导入失败：未获取到文件内容')));
            return;
          }
          String base64Content = base64Encode(file.bytes!);
          newBook = Book(
            name: file.name,
            type: type,
            contentBase64: base64Content,
          );
          booksJson.add(json.encode(newBook.toJson()));
          await prefs.setStringList('books', booksJson);
          if (!context.mounted) return;
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(SnackBar(content: Text('导入成功: ${file.name}')));
        } else {
          // web端epub只做临时展示
          if (file.bytes == null) {
            if (!context.mounted) return;
            ScaffoldMessenger.of(
              context,
            ).showSnackBar(const SnackBar(content: Text('导入失败：未获取到文件内容')));
            return;
          }
          newBook = Book(name: file.name, type: type, isTemp: true);
          // 临时存储到全局变量或内存（此处可扩展）
          _WebTempEpubHolder.bytes = file.bytes!;
          if (!context.mounted) return;
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('已临时导入: ${file.name}，请在本次会话内阅读')),
          );
        }
      } else {
        if (file.path == null) {
          if (!context.mounted) return;
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(const SnackBar(content: Text('导入失败：未获取到文件路径')));
          return;
        }
        String? savePath;
        if (type == 'epub') {
          // 拷贝到应用目录
          final appDir = await getApplicationDocumentsDirectory();
          final newFile = await io.File(
            file.path!,
          ).copy('${appDir.path}/${file.name}');
          savePath = newFile.path;
        } else {
          savePath = file.path!;
        }
        newBook = Book(name: file.name, type: type, path: savePath);
        booksJson.add(json.encode(newBook.toJson()));
        await prefs.setStringList('books', booksJson);
        if (!context.mounted) return;
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(SnackBar(content: Text('导入成功: ${file.name}')));
      }
      if (!context.mounted) return;
      Navigator.of(context).pop();
    } else {
      if (!context.mounted) return;
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(const SnackBar(content: Text('未选择文件或导入已取消')));
    }
  }

  void _showImportSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      builder: (BuildContext ctx) {
        return SafeArea(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ListTile(
                leading: const Icon(Icons.description),
                title: const Text('导入小说 (txt)'),
                onTap: () => _importBook(context, 'txt'),
              ),
              ListTile(
                leading: const Icon(Icons.image),
                title: const Text('导入漫画 (epub)'),
                onTap: () => _importBook(context, 'epub'),
              ),
            ],
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('设置')),
      body: ListView(
        children: [
          SwitchListTile(
            title: const Text('夜间模式'),
            value: Provider.of<ThemeProvider>(context).isDarkMode,
            onChanged: (val) {
              Provider.of<ThemeProvider>(
                context,
                listen: false,
              ).toggleDarkMode(val);
            },
            secondary: const Icon(Icons.nightlight_round),
          ),
          ListTile(
            leading: const Icon(Icons.chrome_reader_mode),
            title: const Text('阅读设置'),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (_) => const ReadingSettingsPage()),
              );
            },
          ),
          ListTile(
            leading: const Icon(Icons.import_contacts),
            title: const Text('导入书籍'),
            onTap: () => _showImportSheet(context),
          ),
          ListTile(
            leading: const Icon(Icons.source),
            title: const Text('书源'),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (_) => const BookSourcePage()),
              );
            },
          ),
        ],
      ),
    );
  }
}

// 在 SettingsPage 之前添加两个占位页面
class SystemSettingsPage extends StatefulWidget {
  const SystemSettingsPage({super.key});
  @override
  State<SystemSettingsPage> createState() => _SystemSettingsPageState();
}

class _SystemSettingsPageState extends State<SystemSettingsPage> {
  final List<Color> _presetColors = [
    Colors.white, // 新增白色
    Color(0xFF1976D2), // 蓝
    Color(0xFF388E3C), // 绿
    Color(0xFFD32F2F), // 红
    Color(0xFF7B1FA2), // 紫
    Color(0xFFF57C00), // 橙
    Color(0xFF455A64), // 灰
    Color(0xFF673AB7), // 默认深紫
  ];

  void _changeTheme(Color color) {
    Provider.of<ThemeProvider>(context, listen: false).setPrimaryColor(color);
    Navigator.of(context).pop(); // 切换后直接返回主界面
  }

  void _showCustomColorDialog() async {
    Color customColor =
        (Provider.of<ThemeProvider>(context, listen: false).primaryColor);
    await showDialog(
      context: context,
      builder: (ctx) {
        return StatefulBuilder(
          builder: (context, setState) {
            return AlertDialog(
              title: const Text('自定义主题色'),
              content: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Slider(
                    value: customColor.r.toDouble(),
                    min: 0,
                    max: 255,
                    label: 'R:  {customColor.r}',
                    activeColor: customColor,
                    thumbColor: customColor,
                    onChanged: (v) {
                      setState(() {
                        customColor = customColor.withRed(v.toInt());
                      });
                    },
                  ),
                  Slider(
                    value: customColor.g.toDouble(),
                    min: 0,
                    max: 255,
                    label: 'G:  {customColor.g}',
                    activeColor: customColor,
                    thumbColor: customColor,
                    onChanged: (v) {
                      setState(() {
                        customColor = customColor.withGreen(v.toInt());
                      });
                    },
                  ),
                  Slider(
                    value: customColor.b.toDouble(),
                    min: 0,
                    max: 255,
                    label: 'B:  {customColor.b}',
                    activeColor: customColor,
                    thumbColor: customColor,
                    onChanged: (v) {
                      setState(() {
                        customColor = customColor.withBlue(v.toInt());
                      });
                    },
                  ),
                  const SizedBox(height: 8),
                  Container(
                    width: 48,
                    height: 48,
                    decoration: BoxDecoration(
                      color: customColor,
                      borderRadius: BorderRadius.circular(8),
                      border: Border.all(color: Colors.grey),
                    ),
                  ),
                ],
              ),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.pop(ctx);
                  },
                  child: const Text('取消'),
                ),
                ElevatedButton(
                  onPressed: () {
                    _changeTheme(customColor); // 这里会自动pop主界面
                    Navigator.pop(ctx);
                  },
                  child: const Text('应用'),
                ),
              ],
            );
          },
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final themeProvider = Provider.of<ThemeProvider>(context);
    return Scaffold(
      appBar: AppBar(title: const Text('系统设置')),
      body: ListView(
        children: [
          const ListTile(leading: Icon(Icons.color_lens), title: Text('主题颜色')),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Wrap(
              spacing: 16,
              children: [
                ..._presetColors.map(
                  (c) => GestureDetector(
                    onTap: () => _changeTheme(c),
                    child: Container(
                      width: 40,
                      height: 40,
                      margin: const EdgeInsets.symmetric(vertical: 8),
                      decoration: BoxDecoration(
                        color: c,
                        border: Border.all(
                          color:
                              (themeProvider.primaryColor == c)
                                  ? (c == Colors.white
                                      ? Colors.grey
                                      : Colors.black)
                                  : Colors.transparent,
                          width: 3,
                        ),
                        borderRadius: BorderRadius.circular(20),
                      ),
                    ),
                  ),
                ),
                GestureDetector(
                  onTap: _showCustomColorDialog,
                  child: Container(
                    width: 40,
                    height: 40,
                    margin: const EdgeInsets.symmetric(vertical: 8),
                    decoration: BoxDecoration(
                      color:
                          Provider.of<ThemeProvider>(
                            context,
                            listen: false,
                          ).primaryColor,
                      border: Border.all(color: Colors.grey, width: 1),
                      borderRadius: BorderRadius.circular(20),
                    ),
                    child: const Icon(Icons.add, color: Colors.white),
                  ),
                ),
              ],
            ),
          ),
          const Divider(),
          const Center(
            child: Text('系统设置内容（占位）', style: TextStyle(color: Colors.grey)),
          ),
        ],
      ),
    );
  }
}

class ReadingSettingsPage extends StatefulWidget {
  final VoidCallback? onSettingsChanged;
  const ReadingSettingsPage({super.key, this.onSettingsChanged});

  @override
  State<ReadingSettingsPage> createState() => _ReadingSettingsPageState();
}

class _ReadingSettingsPageState extends State<ReadingSettingsPage> {
  ReadingSettings _settings = ReadingSettings();
  bool _loading = true;

  // 背景颜色选项
  final List<Map<String, dynamic>> _backgroundColors = [
    {'name': '白色', 'color': Colors.white, 'value': 'white'},
    {'name': '米色', 'color': const Color(0xFFF5F5DC), 'value': 'beige'},
    {'name': '浅黄', 'color': const Color(0xFFFFF8DC), 'value': 'lightYellow'},
    {'name': '浅绿', 'color': const Color(0xFFF0FFF0), 'value': 'lightGreen'},
    {'name': '浅蓝', 'color': const Color(0xFFF0F8FF), 'value': 'lightBlue'},
    {'name': '浅灰', 'color': const Color(0xFFF5F5F5), 'value': 'lightGray'},
    {'name': '深色', 'color': const Color(0xFF2C2C2C), 'value': 'dark'},
  ];

  // 字体选项
  final List<String> _fontFamilies = [
    '系统默认',
    'serif',
    'monospace',
    'cursive',
    'fantasy',
  ];

  @override
  void initState() {
    super.initState();
    _loadSettings();
  }

  Future<void> _loadSettings() async {
    final settings = await ReadingSettingsManager.loadSettings();
    setState(() {
      _settings = settings;
      _loading = false;
    });
  }

  Future<void> _saveSettings() async {
    await ReadingSettingsManager.saveSettings(_settings);
    if (widget.onSettingsChanged != null) widget.onSettingsChanged!();
    if (mounted) {
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(const SnackBar(content: Text('设置已保存')));
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_loading) {
      return Scaffold(
        appBar: AppBar(title: Text('阅读设置')),
        body: Center(child: CircularProgressIndicator()),
      );
    }

    final previewWidget = Container(
      width: double.infinity,
      padding: const EdgeInsets.all(24),
      color: _getBackgroundColor(_settings.backgroundColor),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            '预览文本：这是一段示例文字。\n\n这是第二段，用于预览所有阅读设置效果。',
            style: TextStyle(
              fontSize: _settings.fontSize,
              fontFamily:
                  _settings.fontFamily == '系统默认' ? null : _settings.fontFamily,
              height: _settings.lineHeight,
              color:
                  _settings.backgroundColor == 'dark'
                      ? Colors.white
                      : Colors.black,
            ),
          ),
        ],
      ),
    );

    final settingsList = [
      // 字体大小设置
      Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  const Icon(Icons.text_fields),
                  const SizedBox(width: 8),
                  const Text(
                    '字体大小',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  const Spacer(),
                  Text(
                    '${_settings.fontSize.toInt()}px',
                    style: const TextStyle(fontSize: 14, color: Colors.grey),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Slider(
                value: _settings.fontSize,
                min: 12.0,
                max: 24.0,
                divisions: 12,
                label: '${_settings.fontSize.toInt()}px',
                onChanged: (value) {
                  setState(() {
                    _settings = _settings.copyWith(fontSize: value);
                  });
                },
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 16),
      // 行高设置
      Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  const Icon(Icons.format_line_spacing),
                  const SizedBox(width: 8),
                  const Text(
                    '行高',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  const Spacer(),
                  Text(
                    '${_settings.lineHeight.toStringAsFixed(1)}',
                    style: const TextStyle(fontSize: 14, color: Colors.grey),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Slider(
                value: _settings.lineHeight,
                min: 1.0,
                max: 2.5,
                divisions: 15,
                label: _settings.lineHeight.toStringAsFixed(1),
                onChanged: (value) {
                  setState(() {
                    _settings = _settings.copyWith(lineHeight: value);
                  });
                },
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 16),
      // 字体选择
      Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  const Icon(Icons.font_download),
                  const SizedBox(width: 8),
                  const Text(
                    '字体选择',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              DropdownButtonFormField<String>(
                value: _settings.fontFamily,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: '选择字体',
                ),
                items:
                    _fontFamilies.map((font) {
                      return DropdownMenuItem(
                        value: font,
                        child: Text(
                          font,
                          style: TextStyle(
                            fontFamily: font == '系统默认' ? null : font,
                          ),
                        ),
                      );
                    }).toList(),
                onChanged: (value) {
                  if (value != null) {
                    setState(() {
                      _settings = _settings.copyWith(fontFamily: value);
                    });
                  }
                },
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 16),
      // 段落间距设置
      Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  const Icon(Icons.vertical_align_center),
                  const SizedBox(width: 8),
                  const Text(
                    '段落间距',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  const Spacer(),
                  Text(
                    '${_settings.paragraphSpacing.toInt()}px',
                    style: const TextStyle(fontSize: 14, color: Colors.grey),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Slider(
                value: _settings.paragraphSpacing,
                min: 0.0,
                max: 20.0,
                divisions: 20,
                label: '${_settings.paragraphSpacing.toInt()}px',
                onChanged: (value) {
                  setState(() {
                    _settings = _settings.copyWith(paragraphSpacing: value);
                  });
                },
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 16),
      // 阅读背景设置
      Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  const Icon(Icons.palette),
                  const SizedBox(width: 8),
                  const Text(
                    '阅读背景',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Wrap(
                spacing: 12,
                runSpacing: 12,
                children:
                    _backgroundColors.map((bg) {
                      final isSelected =
                          _settings.backgroundColor == bg['value'];
                      return GestureDetector(
                        onTap: () {
                          setState(() {
                            _settings = _settings.copyWith(
                              backgroundColor: bg['value'],
                            );
                          });
                        },
                        child: Container(
                          width: 60,
                          height: 60,
                          decoration: BoxDecoration(
                            color: bg['color'],
                            border: Border.all(
                              color:
                                  isSelected
                                      ? Provider.of<ThemeProvider>(
                                        context,
                                        listen: false,
                                      ).primaryColor
                                      : Colors.grey[300]!,
                              width: isSelected ? 3 : 1,
                            ),
                            borderRadius: BorderRadius.circular(8),
                          ),
                          child: Center(
                            child: Text(
                              bg['name'],
                              style: TextStyle(
                                fontSize: 12,
                                color:
                                    bg['value'] == 'dark'
                                        ? Colors.white
                                        : Colors.black,
                                fontWeight:
                                    isSelected
                                        ? FontWeight.bold
                                        : FontWeight.normal,
                              ),
                            ),
                          ),
                        ),
                      );
                    }).toList(),
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 16),
      // 亮度调节
      Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  const Icon(Icons.brightness_6),
                  const SizedBox(width: 8),
                  const Text(
                    '亮度调节',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  const Spacer(),
                  Text(
                    '${(_settings.brightness * 100).toInt()}%',
                    style: const TextStyle(fontSize: 14, color: Colors.grey),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Slider(
                value: _settings.brightness,
                min: 0.3,
                max: 1.0,
                divisions: 7,
                label: '${(_settings.brightness * 100).toInt()}%',
                onChanged: (value) {
                  setState(() {
                    _settings = _settings.copyWith(brightness: value);
                  });
                },
              ),
            ],
          ),
        ),
      ),
      const SizedBox(height: 32),
      // 保存按钮
      Row(
        children: [
          Expanded(
            child: ElevatedButton.icon(
              onPressed: _saveSettings,
              icon: const Icon(Icons.save),
              label: const Text('保存设置'),
              style: ElevatedButton.styleFrom(
                padding: const EdgeInsets.symmetric(vertical: 16),
              ),
            ),
          ),
          const SizedBox(width: 16),
          Expanded(
            child: OutlinedButton.icon(
              onPressed: () async {
                setState(() {
                  _settings = ReadingSettings();
                });
                await ReadingSettingsManager.saveSettings(_settings);
                if (widget.onSettingsChanged != null)
                  widget.onSettingsChanged!();
                if (mounted) {
                  ScaffoldMessenger.of(
                    context,
                  ).showSnackBar(const SnackBar(content: Text('已恢复默认设置')));
                }
              },
              icon: const Icon(Icons.refresh),
              label: const Text('恢复默认'),
              style: OutlinedButton.styleFrom(
                padding: const EdgeInsets.symmetric(vertical: 16),
              ),
            ),
          ),
        ],
      ),
    ];

    final isDesktop = MediaQuery.of(context).size.width > 600;

    return Scaffold(
      appBar: AppBar(title: Text('阅读设置')),
      body:
          isDesktop
              ? Row(
                children: [
                  Expanded(
                    flex: 2,
                    child: ListView(
                      padding: const EdgeInsets.all(24),
                      children: settingsList,
                    ),
                  ),
                  const VerticalDivider(width: 1),
                  Expanded(flex: 3, child: previewWidget),
                ],
              )
              : ListView(
                padding: const EdgeInsets.all(16.0),
                children: [...settingsList, previewWidget],
              ),
    );
  }

  Color _getBackgroundColor(String colorName) {
    switch (colorName) {
      case 'white':
        return Colors.white;
      case 'beige':
        return const Color(0xFFF5F5DC);
      case 'lightYellow':
        return const Color(0xFFFFF8DC);
      case 'lightGreen':
        return const Color(0xFFF0FFF0);
      case 'lightBlue':
        return const Color(0xFFF0F8FF);
      case 'lightGray':
        return const Color(0xFFF5F5F5);
      case 'dark':
        return const Color(0xFF2C2C2C);
      default:
        return Colors.white;
    }
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _selectedIndex = 0;

  static const List<Widget> _pages = <Widget>[
    BookshelfPage(),
    SettingsPage(),
    AboutPage(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (isDesktop()) {
      // 桌面端：左侧导航栏
      return Scaffold(
        body: Container(
          color:
              Provider.of<ThemeProvider>(context).primaryColor == Colors.white
                  ? Colors.white
                  : Theme.of(context).colorScheme.surface,
          child: Row(
            children: [
              NavigationRail(
                selectedIndex: _selectedIndex,
                onDestinationSelected: _onItemTapped,
                labelType: NavigationRailLabelType.all,
                destinations: const [
                  NavigationRailDestination(
                    icon: Icon(Icons.book),
                    label: Text('书架'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.settings),
                    label: Text('设置'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.info_outline),
                    label: Text('关于我们'),
                  ),
                ],
              ),
              const VerticalDivider(width: 1),
              Expanded(child: _pages[_selectedIndex]),
            ],
          ),
        ),
      );
    } else {
      // 移动端：底部导航栏
      return Scaffold(
        body: _pages[_selectedIndex],
        bottomNavigationBar: BottomNavigationBar(
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(icon: Icon(Icons.book), label: '书架'),
            BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
            BottomNavigationBarItem(
              icon: Icon(Icons.info_outline),
              label: '关于我们',
            ),
          ],
          currentIndex: _selectedIndex,
          selectedItemColor: Theme.of(context).colorScheme.primary,
          onTap: _onItemTapped,
        ),
      );
    }
  }
}

// 解析epub，返回章节列表（支持文本和图片）
Future<List<EpubChapter>> parseEpubChapters(Book book) async {
  Uint8List? bytes;
  if (book.isTemp && kIsWeb) {
    bytes = _WebTempEpubHolder.bytes;
  } else if (book.path != null) {
    if (kIsWeb) return [];
    try {
      final file = io.File(book.path!);
      bytes = await file.readAsBytes();
    } catch (_) {
      return [];
    }
  }
  if (bytes == null) return [];

  final epubBook = await EpubReader.readBook(bytes);

  List<EpubChapter> chapters = [];
  for (final chapter in epubBook.Chapters!) {
    // 1. 先查找图片
    List<Uint8List> images = [];
    void extractImages(String? html) {
      if (html == null) return;
      final imgSrcs =
          RegExp(r'<img[^>]+src="([^"]+)"')
              .allMatches(html)
              .map((m) => m.group(1))
              .whereType<String>()
              .toList();
      for (final src in imgSrcs) {
        // 兼容不同路径写法（结尾模糊匹配）
        MapEntry<String, EpubByteContentFile>? imgEntry;
        if (epubBook.Content?.Images != null) {
          for (final entry in epubBook.Content!.Images!.entries) {
            if (entry.key
                .replaceAll('\\', '/')
                .endsWith(src.replaceAll('\\', '/'))) {
              imgEntry = entry;
              break;
            }
          }
        }
        if (imgEntry != null && imgEntry.value.Content != null) {
          images.add(Uint8List.fromList(imgEntry.value.Content!));
        }
      }
    }

    extractImages(chapter.HtmlContent);
    if (chapter.SubChapters != null) {
      for (final sub in chapter.SubChapters!) {
        extractImages(sub.HtmlContent);
      }
    }

    if (images.isNotEmpty) {
      chapters.add(EpubChapter(title: chapter.Title ?? '图片章节', images: images));
    } else if (chapter.HtmlContent != null && chapter.HtmlContent!.isNotEmpty) {
      // 没有图片则作为文本
      final text = removeHtmlTags(chapter.HtmlContent!);
      chapters.add(
        EpubChapter(title: chapter.Title ?? '章节', textContent: text),
      );
    }
  }
  return chapters;
}

String removeHtmlTags(String html) {
  return RegExp(r'<[^>]+>')
      .allMatches(html)
      .fold(html, (prev, match) => prev.replaceAll(match.group(0)!, ''));
}

// 解析epub漫画章节，只提取图片key，并返回imagesMap
Future<(List<ComicChapter>, Map<String, EpubByteContentFile>)> parseComicEpub(
  Book book,
) async {
  Uint8List? bytes;
  if (book.isTemp && kIsWeb) {
    bytes = _WebTempEpubHolder.bytes;
  } else if (book.path != null) {
    if (kIsWeb) return (<ComicChapter>[], <String, EpubByteContentFile>{});
    try {
      final file = io.File(book.path!);
      bytes = await file.readAsBytes();
    } catch (_) {
      return (<ComicChapter>[], <String, EpubByteContentFile>{});
    }
  }
  if (bytes == null) return (<ComicChapter>[], <String, EpubByteContentFile>{});
  final epubBook = await EpubReader.readBook(bytes);
  final imagesMap = epubBook.Content?.Images ?? <String, EpubByteContentFile>{};
  List<ComicChapter> chapters = [];
  void extractChapters(List<dynamic>? epubChapters) {
    if (epubChapters == null) return;
    for (final chapter in epubChapters) {
      chapters.add(
        ComicChapter(
          title: chapter.Title ?? '图片章节',
          htmlContent: chapter.HtmlContent,
          fileName: null, // 不再赋值FileName，避免NoSuchMethodError
          subChapters: chapter.SubChapters ?? [],
        ),
      );
    }
  }

  extractChapters(List<dynamic>.from(epubBook.Chapters!));
  return (chapters, imagesMap);
}

List<String> extractImageKeysFromHtml(
  String html,
  Map<String, EpubByteContentFile> imagesMap,
) {
  final imgSrcs =
      RegExp(
        r'<img[^>]+src="([^"]+)"',
      ).allMatches(html).map((m) => m.group(1)).whereType<String>().toList();
  List<String> result = [];
  for (final src in imgSrcs) {
    final entry = imagesMap.entries.firstWhere(
      (e) => e.key.replaceAll('\\', '/').endsWith(src.replaceAll('\\', '/')),
      orElse:
          () =>
              MapEntry<String, EpubByteContentFile>('', EpubByteContentFile()),
    );
    if (entry.key.isNotEmpty) {
      result.add(entry.key);
    }
  }
  return result;
}

// 异步提取图片key
Future<List<String>> extractImageKeysFromHtmlAsync(
  String? html,
  Map<String, EpubByteContentFile> imagesMap,
) async {
  if (html == null) return [];
  final imgSrcs =
      RegExp(
        r'<img[^>]+src="([^"]+)"',
      ).allMatches(html).map((m) => m.group(1)).whereType<String>().toList();
  List<String> result = [];
  for (final src in imgSrcs) {
    String srcFileName = src.split('/').last;
    final entry = imagesMap.entries.firstWhere(
      (e) => e.key.split('/').last == srcFileName,
      orElse:
          () =>
              MapEntry<String, EpubByteContentFile>('', EpubByteContentFile()),
    );
    if (entry.key.isNotEmpty) {
      result.add(entry.key);
    }
  }
  return result;
}

// 工具函数：递归拉平成一维章节列表
List<ComicChapter> flattenChapters(List<ComicChapter> chapters) {
  List<ComicChapter> result = [];
  for (final chapter in chapters) {
    result.add(chapter);
    if (chapter.subChapters.isNotEmpty) {
      result.addAll(
        flattenChapters(List<ComicChapter>.from(chapter.subChapters)),
      );
    }
  }
  return result;
}

// ComicReaderPage进入章节时异步提取图片key并加载
class ComicReaderPage extends StatefulWidget {
  final List<ComicChapter> chapters;
  final Map<String, EpubByteContentFile> imagesMap;
  const ComicReaderPage({
    super.key,
    required this.chapters,
    required this.imagesMap,
  });
  @override
  State<ComicReaderPage> createState() => _ComicReaderPageState();
}

class _ComicReaderPageState extends State<ComicReaderPage> {
  int _selectedChapter = 0;
  late List<ComicChapter> _flatChapters;
  Future<List<String>>? _imageKeysFuture;
  double _imageScale = 1.0; // 图片缩放比例
  double _imageBrightness = 1.0; // 图片亮度，1.0为正常
  bool _grayMode = false; // 黑白（灰度）模式
  static const List<double> _grayMatrix = [
    0.2126,
    0.7152,
    0.0722,
    0,
    0,
    0.2126,
    0.7152,
    0.0722,
    0,
    0,
    0.2126,
    0.7152,
    0.0722,
    0,
    0,
    0,
    0,
    0,
    1,
    0,
  ];
  // 目录收起/展开
  bool _chapterListCollapsed = false;
  final ScrollController _chapterListScrollController = ScrollController();
  // 全屏/沉浸模式
  bool _fullscreen = false;
  final FocusNode _focusNode = FocusNode();
  final TextEditingController _searchController = TextEditingController();
  final FocusNode _searchFieldFocusNode = FocusNode();

  @override
  void initState() {
    super.initState();
    _flatChapters = flattenChapters(widget.chapters);
    _imageKeysFuture = extractImageKeysFromHtmlAsync(
      _flatChapters[_selectedChapter].htmlContent,
      widget.imagesMap,
    );
  }

  void _onChapterChanged(int idx) {
    setState(() {
      _selectedChapter = idx;
      _imageKeysFuture = extractImageKeysFromHtmlAsync(
        _flatChapters[idx].htmlContent,
        widget.imagesMap,
      );
      // 自动滚动高亮项到可见区域
      if (_chapterListScrollController.hasClients) {
        // 40为每项高度
        _chapterListScrollController.animateTo(
          (idx - 2).clamp(0, _flatChapters.length - 1) * 40.0,
          duration: const Duration(milliseconds: 300),
          curve: Curves.ease,
        );
      }
    });
  }

  Future<Uint8List?> _loadImage(String key) async {
    final file = widget.imagesMap[key];
    if (file != null && file.Content != null) {
      return Uint8List.fromList(file.Content!);
    }
    return null;
  }

  List<Widget> _buildScaleControlsRow() {
    return [
      IconButton(
        icon: const Icon(Icons.zoom_out),
        tooltip: '缩小',
        onPressed: () {
          setState(() {
            _imageScale = (_imageScale - 0.1).clamp(0.2, 3.0);
          });
        },
      ),
      Text(
        '${(_imageScale * 100).toInt()}%',
        style: const TextStyle(fontSize: 15),
      ),
      IconButton(
        icon: const Icon(Icons.zoom_in),
        tooltip: '放大',
        onPressed: () {
          setState(() {
            _imageScale = (_imageScale + 0.1).clamp(0.2, 3.0);
          });
        },
      ),
      IconButton(
        icon: const Icon(Icons.refresh),
        tooltip: '重置缩放',
        onPressed: () {
          setState(() {
            _imageScale = 1.0;
          });
        },
      ),
    ];
  }

  List<Widget> _buildBrightnessControlsRow({bool showPercent = false}) {
    return [
      const Icon(Icons.brightness_6, size: 20),
      SizedBox(
        width: 100,
        child: Slider(
          value: _imageBrightness,
          min: 0.05,
          max: 2.0,
          divisions: 39,
          label: '${(_imageBrightness * 100).toInt()}%',
          onChanged: (v) {
            setState(() {
              _imageBrightness = v;
            });
          },
        ),
      ),
      if (showPercent)
        Padding(
          padding: const EdgeInsets.only(left: 6),
          child: Text(
            '${(_imageBrightness * 100).toInt()}%',
            style: const TextStyle(fontSize: 15),
          ),
        ),
      IconButton(
        icon: Icon(
          _grayMode ? Icons.filter_b_and_w : Icons.filter_b_and_w_outlined,
        ),
        tooltip: _grayMode ? '关闭黑白' : '黑白模式',
        onPressed: () {
          setState(() {
            _grayMode = !_grayMode;
          });
        },
      ),
    ];
  }

  Widget _buildControls(bool isDesktop) {
    if (isDesktop) {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Card(
            margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: _buildScaleControlsRow(),
              ),
            ),
          ),
          Card(
            margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: _buildBrightnessControlsRow(showPercent: true),
              ),
            ),
          ),
        ],
      );
    } else {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ..._buildScaleControlsRow(),
          const SizedBox(width: 16),
          ..._buildBrightnessControlsRow(showPercent: true),
        ],
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final chapter = _flatChapters[_selectedChapter];
    final isDesktop = MediaQuery.of(context).size.width > 600;
    final theme = Theme.of(context);
    final cardColor = theme.cardColor;
    final textColor = theme.textTheme.bodyLarge?.color ?? Colors.black;
    final bgColor = theme.scaffoldBackgroundColor;
    Widget contentWidget = FutureBuilder<List<String>>(
      future: _imageKeysFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        }
        if (!snapshot.hasData) {
          return const Center(child: CircularProgressIndicator());
        }
        final imageKeys = snapshot.data!;
        return SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              LayoutBuilder(
                builder: (context, constraints) {
                  if (constraints.maxWidth > 400) {
                    return _buildControls(isDesktop);
                  } else {
                    return const SizedBox.shrink();
                  }
                },
              ),
              if (chapter.fileName != null)
                Padding(
                  padding: const EdgeInsets.only(top: 16, bottom: 8),
                  child: Text(
                    chapter.fileName!,
                    style: TextStyle(
                      color: textColor.withOpacity(0.7),
                      fontSize: 13,
                    ),
                  ),
                ),
              if (chapter.htmlContent != null)
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  child: Html(
                    data: chapter.htmlContent!,
                    style: {
                      "body": Style(color: textColor, backgroundColor: bgColor),
                    },
                  ),
                ),
              if (imageKeys.isNotEmpty)
                ...imageKeys.map(
                  (key) => FutureBuilder<Uint8List?>(
                    future: _loadImage(key),
                    builder: (context, imgSnap) {
                      if (!imgSnap.hasData) {
                        return const Center(child: CircularProgressIndicator());
                      }
                      return Padding(
                        padding: const EdgeInsets.symmetric(vertical: 8),
                        child: LayoutBuilder(
                          builder: (context, constraints) {
                            final displayWidth =
                                constraints.maxWidth * _imageScale;
                            final maxHeight =
                                MediaQuery.of(context).size.height * 0.8;
                            return RepaintBoundary(
                              child: ColorFiltered(
                                colorFilter:
                                    _grayMode
                                        ? ColorFilter.matrix(_grayMatrix)
                                        : ColorFilter.matrix([
                                          _imageBrightness,
                                          0,
                                          0,
                                          0,
                                          0,
                                          0,
                                          _imageBrightness,
                                          0,
                                          0,
                                          0,
                                          0,
                                          0,
                                          _imageBrightness,
                                          0,
                                          0,
                                          0,
                                          0,
                                          0,
                                          1,
                                          0,
                                        ]),
                                child: flutter.Image.memory(
                                  imgSnap.data!,
                                  fit: BoxFit.contain,
                                  width: displayWidth,
                                  height: maxHeight,
                                ),
                              ),
                            );
                          },
                        ),
                      );
                    },
                  ),
                ),
              if (chapter.htmlContent == null && imageKeys.isEmpty)
                Center(
                  child: Text('本章节无内容', style: TextStyle(color: textColor)),
                ),
            ],
          ),
        );
      },
    );
    // 桌面端全屏/快捷键支持
    if (isDesktop) {
      return Focus(
        focusNode: _focusNode,
        autofocus: true,
        onKey: (node, event) {
          if (event is RawKeyDownEvent) {
            // ←/→切换章节
            if (event.logicalKey == LogicalKeyboardKey.arrowLeft &&
                _selectedChapter > 0) {
              _onChapterChanged(_selectedChapter - 1);
              return KeyEventResult.handled;
            }
            if (event.logicalKey == LogicalKeyboardKey.arrowRight &&
                _selectedChapter < _flatChapters.length - 1) {
              _onChapterChanged(_selectedChapter + 1);
              return KeyEventResult.handled;
            }
            // Ctrl+B 黑白模式
            if (event.isControlPressed &&
                event.logicalKey == LogicalKeyboardKey.keyB) {
              setState(() {
                _grayMode = !_grayMode;
              });
              return KeyEventResult.handled;
            }
            // Ctrl+F 聚焦搜索框
            if (event.isControlPressed &&
                event.logicalKey == LogicalKeyboardKey.keyF) {
              _searchController.selection = TextSelection(
                baseOffset: 0,
                extentOffset: _searchController.text.length,
              );
              FocusScope.of(context).requestFocus(_searchFieldFocusNode);
              return KeyEventResult.handled;
            }
            // F11 全屏切换
            if (event.logicalKey == LogicalKeyboardKey.f11) {
              setState(() {
                _fullscreen = !_fullscreen;
              });
              return KeyEventResult.handled;
            }
          }
          return KeyEventResult.ignored;
        },
        child: Scaffold(
          appBar:
              _fullscreen
                  ? null
                  : AppBar(
                    title: Text(chapter.title),
                    actions: [
                      IconButton(
                        icon: Icon(
                          _fullscreen
                              ? Icons.fullscreen_exit
                              : Icons.fullscreen,
                        ),
                        tooltip: _fullscreen ? '退出全屏' : '全屏',
                        onPressed: () {
                          setState(() {
                            _fullscreen = !_fullscreen;
                          });
                        },
                      ),
                    ],
                  ),
          body: Row(
            children: [
              if (!_fullscreen)
                AnimatedContainer(
                  duration: const Duration(milliseconds: 200),
                  width: _chapterListCollapsed ? 28 : 220,
                  margin: const EdgeInsets.only(left: 16, top: 16, bottom: 16),
                  child:
                      _chapterListCollapsed
                          ? Column(
                            children: [
                              IconButton(
                                icon: const Icon(Icons.chevron_right),
                                tooltip: '展开目录',
                                onPressed: () {
                                  setState(() {
                                    _chapterListCollapsed = false;
                                  });
                                },
                              ),
                            ],
                          )
                          : Material(
                            elevation: 8,
                            borderRadius: BorderRadius.circular(14),
                            color: cardColor,
                            child: Container(
                              height: double.infinity,
                              padding: const EdgeInsets.symmetric(vertical: 8),
                              child: Column(
                                children: [
                                  // 搜索框
                                  Padding(
                                    padding: const EdgeInsets.all(10),
                                    child: TextField(
                                      controller: _searchController,
                                      decoration: InputDecoration(
                                        hintText: '搜索章节...',
                                        prefixIcon: Icon(
                                          Icons.search,
                                          size: 20,
                                        ),
                                        filled: true,
                                        fillColor:
                                            theme.brightness == Brightness.dark
                                                ? const Color(0xFF232323)
                                                : Colors.grey[100],
                                        contentPadding:
                                            const EdgeInsets.symmetric(
                                              vertical: 8,
                                            ),
                                        border: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(
                                            6,
                                          ),
                                          borderSide: BorderSide.none,
                                        ),
                                        isDense: true,
                                      ),
                                      onChanged: (val) {
                                        setState(() {});
                                      },
                                    ),
                                  ),
                                  // 章节列表
                                  Expanded(
                                    child: ListView.separated(
                                      controller: _chapterListScrollController,
                                      itemCount: _flatChapters.length,
                                      separatorBuilder:
                                          (_, __) => Divider(
                                            height: 1,
                                            color: theme.dividerColor,
                                          ),
                                      itemBuilder: (context, idx) {
                                        final selected =
                                            idx == _selectedChapter;
                                        return InkWell(
                                          onTap: () => _onChapterChanged(idx),
                                          child: Container(
                                            color:
                                                selected
                                                    ? theme.colorScheme.primary
                                                        .withAlpha(30)
                                                    : Colors.transparent,
                                            height: 40,
                                            child: Row(
                                              children: [
                                                Container(
                                                  width: 4,
                                                  height: 24,
                                                  color:
                                                      selected
                                                          ? theme
                                                              .colorScheme
                                                              .primary
                                                          : Colors.transparent,
                                                ),
                                                const SizedBox(width: 8),
                                                Expanded(
                                                  child: Text(
                                                    _flatChapters[idx].title,
                                                    style: TextStyle(
                                                      fontWeight:
                                                          selected
                                                              ? FontWeight.bold
                                                              : FontWeight
                                                                  .normal,
                                                      color:
                                                          selected
                                                              ? theme
                                                                  .colorScheme
                                                                  .primary
                                                              : textColor,
                                                      fontSize: 15,
                                                    ),
                                                    maxLines: 1,
                                                    overflow:
                                                        TextOverflow.ellipsis,
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        );
                                      },
                                    ),
                                  ),
                                  IconButton(
                                    icon: const Icon(Icons.chevron_left),
                                    tooltip: '收起目录',
                                    onPressed: () {
                                      setState(() {
                                        _chapterListCollapsed = true;
                                      });
                                    },
                                  ),
                                ],
                              ),
                            ),
                          ),
                ),
              // 内容区
              Expanded(child: Container(color: bgColor, child: contentWidget)),
            ],
          ),
        ),
      );
    } else {
      // ...原移动端代码...
      return Scaffold(
        appBar: AppBar(
          title: Text(chapter.title),
          actions: [
            IconButton(
              icon: const Icon(Icons.menu_book),
              onPressed: () => _showChapterSheet(context),
            ),
          ],
        ),
        body: Container(color: bgColor, child: contentWidget),
      );
    }
  }

  void _showChapterSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      builder:
          (ctx) => ListView.builder(
            itemCount: _flatChapters.length,
            itemBuilder:
                (context, idx) => ListTile(
                  title: Text(_flatChapters[idx].title),
                  selected: idx == _selectedChapter,
                  onTap: () {
                    Navigator.pop(context);
                    _onChapterChanged(idx);
                  },
                ),
          ),
    );
  }

  @override
  void dispose() {
    _chapterListScrollController.dispose();
    _focusNode.dispose();
    _searchController.dispose();
    _searchFieldFocusNode.dispose();
    super.dispose();
  }
}

// 阅读设置数据模型
class ReadingSettings {
  final double fontSize;
  final double lineHeight;
  final String fontFamily;
  final double paragraphSpacing;
  final String backgroundColor;
  final double brightness;

  ReadingSettings({
    this.fontSize = 16.0,
    this.lineHeight = 1.5,
    this.fontFamily = '系统默认',
    this.paragraphSpacing = 8.0,
    this.backgroundColor = 'white',
    this.brightness = 1.0,
  });

  Map<String, dynamic> toJson() => {
    'fontSize': fontSize,
    'lineHeight': lineHeight,
    'fontFamily': fontFamily,
    'paragraphSpacing': paragraphSpacing,
    'backgroundColor': backgroundColor,
    'brightness': brightness,
  };

  factory ReadingSettings.fromJson(Map<String, dynamic> json) =>
      ReadingSettings(
        fontSize: json['fontSize']?.toDouble() ?? 16.0,
        lineHeight: json['lineHeight']?.toDouble() ?? 1.5,
        fontFamily: json['fontFamily'] ?? '系统默认',
        paragraphSpacing: json['paragraphSpacing']?.toDouble() ?? 8.0,
        backgroundColor: json['backgroundColor'] ?? 'white',
        brightness: json['brightness']?.toDouble() ?? 1.0,
      );

  ReadingSettings copyWith({
    double? fontSize,
    double? lineHeight,
    String? fontFamily,
    double? paragraphSpacing,
    String? backgroundColor,
    double? brightness,
  }) {
    return ReadingSettings(
      fontSize: fontSize ?? this.fontSize,
      lineHeight: lineHeight ?? this.lineHeight,
      fontFamily: fontFamily ?? this.fontFamily,
      paragraphSpacing: paragraphSpacing ?? this.paragraphSpacing,
      backgroundColor: backgroundColor ?? this.backgroundColor,
      brightness: brightness ?? this.brightness,
    );
  }
}

// 阅读设置管理类
class ReadingSettingsManager {
  static const String _key = 'reading_settings';

  static Future<ReadingSettings> loadSettings() async {
    final prefs = await SharedPreferences.getInstance();
    final json = prefs.getString(_key);
    if (json != null) {
      try {
        return ReadingSettings.fromJson(jsonDecode(json));
      } catch (_) {
        return ReadingSettings();
      }
    }
    return ReadingSettings();
  }

  static Future<void> saveSettings(ReadingSettings settings) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_key, jsonEncode(settings.toJson()));
  }
}

// Web端epub临时内容存储
class _WebTempEpubHolder {
  static Uint8List? bytes;
}

// 1. BookSourcePage页面实现
class BookSourcePage extends StatefulWidget {
  const BookSourcePage({super.key});
  @override
  State<BookSourcePage> createState() => _BookSourcePageState();
}

class _BookSourcePageState extends State<BookSourcePage> {
  final TextEditingController _searchController = TextEditingController();
  List<String> _sources = ['示例书源A', '示例书源B', '示例书源C'];
  String _search = '';

  @override
  Widget build(BuildContext context) {
    final filtered =
        _search.isEmpty
            ? _sources
            : _sources.where((s) => s.contains(_search)).toList();
    return Scaffold(
      appBar: AppBar(title: const Text('书源管理')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(12.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _searchController,
                    decoration: InputDecoration(
                      hintText: '搜索书源...',
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(8),
                        borderSide: BorderSide.none,
                      ),
                      filled: true,
                      fillColor:
                          Theme.of(context).brightness == Brightness.dark
                              ? const Color(0xFF232323)
                              : Colors.grey[100],
                      isDense: true,
                      contentPadding: const EdgeInsets.symmetric(
                        vertical: 10,
                        horizontal: 12,
                      ),
                    ),
                    onChanged: (val) {
                      setState(() {
                        _search = val.trim();
                      });
                    },
                  ),
                ),
                const SizedBox(width: 8),
                IconButton(
                  icon: const Icon(Icons.add),
                  tooltip: '添加书源',
                  onPressed: () {
                    // 目前仅弹窗提示
                    showDialog(
                      context: context,
                      builder:
                          (ctx) => AlertDialog(
                            title: const Text('添加书源'),
                            content: const Text('添加书源功能暂未实现'),
                            actions: [
                              TextButton(
                                onPressed: () => Navigator.pop(ctx),
                                child: const Text('确定'),
                              ),
                            ],
                          ),
                    );
                  },
                ),
              ],
            ),
          ),
          const Divider(height: 1),
          Expanded(
            child:
                filtered.isEmpty
                    ? const Center(child: Text('暂无书源'))
                    : ListView.separated(
                      itemCount: filtered.length,
                      separatorBuilder: (_, __) => const Divider(height: 1),
                      itemBuilder:
                          (context, idx) => ListTile(
                            leading: const Icon(Icons.source),
                            title: Text(filtered[idx]),
                            onTap: () {},
                          ),
                    ),
          ),
        ],
      ),
    );
  }
}

// 2. 设置页"书源"点击跳转BookSourcePage

// 新增AboutPage页面
class AboutPage extends StatelessWidget {
  const AboutPage({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('关于我们')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: const [
            Icon(Icons.menu_book, size: 64, color: Colors.blueGrey),
            SizedBox(height: 24),
            Text(
              '书阅',
              style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 12),
            Text(
              '书阅 © 2024',
              style: TextStyle(fontSize: 16, color: Colors.grey),
            ),
            SizedBox(height: 8),
            Text('作者：XXX', style: TextStyle(fontSize: 15)),
            SizedBox(height: 24),
            Text('感谢使用书阅，祝您阅读愉快！', style: TextStyle(fontSize: 15)),
          ],
        ),
      ),
    );
  }
}

// --- Isolate章节分割 ---
Future<List<ChapterInfo>> splitChaptersInIsolate(String content) async {
  return await compute(_splitChaptersSync, content);
}

List<ChapterInfo> _splitChaptersSync(String content) {
  print(
    '[DEBUG] isolate章节分割: 内容前200字: ${content.substring(0, content.length > 200 ? 200 : content.length).replaceAll(RegExp(r'\s'), ' ')}',
  );
  // 宽松正则，兼容序章、楔子、引子、尾声、番外、附录、前言、跋、序、终章、尾章、开篇、新书、完结、正文、引言、前传、后传、预告、彩蛋等特殊章节，以及"第xx章/节/回/集/卷"等
  final chapterReg = RegExp(
    r'(^((序章|楔子|引子|尾声|后记|番外|附录|前言|跋|序|终章|尾章|开篇|新书|完结|正文|引言|前传|后传|预告|彩蛋)[^\n\r]*|[第]?[0-9零一二三四五六七八九十百千万]+[章节回集卷][^\n\r]*))',
    multiLine: true,
  );
  final matches = chapterReg.allMatches(content).toList();
  print('[DEBUG] isolate章节分割: 命中章节数=${matches.length}');
  for (int i = 0; i < matches.length; i++) {
    print('[DEBUG] isolate章节分割: 章节 $i: title="${matches[i].group(0)?.trim()}"');
  }
  if (matches.isEmpty) {
    return [ChapterInfo(title: '正文', start: 0, end: content.length)];
  }
  List<ChapterInfo> chapters = [];
  for (int i = 0; i < matches.length; i++) {
    final m = matches[i];
    final start = m.start;
    final end =
        (i + 1 < matches.length) ? matches[i + 1].start : content.length;
    final title = m.group(0)?.trim() ?? '章节';
    chapters.add(ChapterInfo(title: title, start: start, end: end));
  }
  return chapters;
}

// 分块流式分割章节，适合大文件，支持进度回调
Future<List<ChapterInfo>> splitChaptersStream(
  String filePath, {
  void Function(double progress)? onProgress,
}) async {
  final file = io.File(filePath);
  final fileLength = await file.length();
  final raf = await file.open();
  // 新正则，兼容序章、楔子、引子、尾声、番外、附录、前言、跋、序、终章、尾章、开篇、新书、完结、正文、引言、前传、后传、预告、彩蛋等特殊章节，以及"第xx章/节/回/集/卷"等
  final chapterReg = RegExp(
    r'(^((序章|楔子|引子|尾声|后记|番外|附录|前言|跋|序|终章|尾章|开篇|新书|完结|正文|引言|前传|后传|预告|彩蛋)[^\n\r]*|[第]?[0-9零一二三四五六七八九十百千万]+[章节回集卷][^\n\r]*))',
    multiLine: true,
  );
  List<ChapterInfo> chapters = [];
  String buffer = '';
  int offset = 0;
  const chunkSize = 1024 * 1024; // 1MB
  int readBytes = 0;
  int lastChapterStart = 0;
  String? lastChapterTitle;
  List<_TempChapter> tempChapters = [];

  // 1. 先检测编码
  await raf.setPosition(0);
  final firstBytes = await raf.read(2048);
  String Function(List<int>) decoder;
  try {
    utf8.decode(firstBytes);
    decoder = (b) => utf8.decode(b, allowMalformed: true);
    print('[DEBUG] splitChaptersStream: 检测到UTF-8编码');
  } catch (_) {
    decoder = (b) => gbk.decode(b);
    print('[DEBUG] splitChaptersStream: 检测到GBK编码');
  }
  await raf.setPosition(0);

  while (true) {
    final bytes = await raf.read(chunkSize);
    if (bytes.isEmpty) break;
    readBytes += bytes.length;
    buffer += decoder(bytes);

    final matches = chapterReg.allMatches(buffer).toList();
    final preview = buffer.length > 100 ? buffer.substring(0, 100) : buffer;
    print(
      '[DEBUG] 分块: buffer.length=${buffer.length}, 命中章节数=${matches.length}, 前100字: ${preview.replaceAll(RegExp(r'\s'), ' ')}',
    );
    if (matches.isNotEmpty) {
      for (int i = 0; i < matches.length; i++) {
        final m = matches[i];
        final title = m.group(0)!.trim();
        final start = m.start;
        tempChapters.add(_TempChapter(title: title, start: offset + start));
      }
      // 只保留最后一个匹配后的内容到下一轮
      if (matches.length > 0) {
        final last = matches.last;
        buffer = buffer.substring(last.start);
        offset += last.start;
      }
    } else {
      // 没有匹配，缓冲区太小，继续读
      if (buffer.length > 10 * 1024 * 1024) {
        // 超过10MB还没命中章节
        print('[WARN] buffer超大且无章节命中，强制分割为一章，避免死循环');
        tempChapters.add(
          _TempChapter(title: buffer.split('\n').first.trim(), start: offset),
        );
        buffer = '';
        offset += readBytes;
        break;
      }
    }
    if (onProgress != null) {
      onProgress(readBytes / fileLength);
    }
  }
  // 处理最后一章
  if (buffer.isNotEmpty) {
    tempChapters.add(
      _TempChapter(title: buffer.split('\n').first.trim(), start: offset),
    );
  }
  // 生成章节区间
  for (int i = 0; i < tempChapters.length; i++) {
    final start = tempChapters[i].start;
    final end =
        (i + 1 < tempChapters.length) ? tempChapters[i + 1].start : fileLength;
    chapters.add(
      ChapterInfo(title: tempChapters[i].title, start: start, end: end),
    );
  }
  await raf.close();
  if (onProgress != null) {
    onProgress(1.0);
  }
  return chapters;
}

class _TempChapter {
  final String title;
  final int start;
  _TempChapter({required this.title, required this.start});
}
